<?php
namespace WDB\Query;
use WDB;

/**
 * Query structure base class.
 *
 * Query structure is developed for object-style building SQL queries (change any part of the query anytime!
 * not just wrap query in another like some database libraries do).
 * This base class contains structure parts which are common for all query types:
 * - table
 * - bound database
 *
 * @author Richard Ejem <richard(at)ejem.cz>
 * @package WDB
 *
 * @property Element\iTableSource $table
 */
abstract class Query extends \WDB\BaseObject
{
    /**@var Element\iTableSource*/
    protected $table;
    /**@var WDB\Database|NULL*/
    protected $database;

    public function __construct()
    {
        $this->table = new Element\Dual();
    }
    // <editor-fold defaultstate="collapsed" desc="FROM clause">
    /**
     * Get current table source.
     *
     * @return Element\iTableSource
     */
    public function getTable()
    {
        return $this->table;
    }

    /**
     * Set table source.
     *
     * @param Element\iTableSource|string|null table name or source object (or null for no-table queries)
     * @return Query fluent interface
     * @throws WDB\Exception\BadArgument
     */
    public function setTable($what)
    {
        if ($what === NULL) $what = new Element\Dual();
        if (! $what instanceof Element\iTableSource) $what = new Element\TableIdentifier($what);
        $this->table = $what;
        return $this;
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Database binding and query execution">
    /**
     * Bind database to this query. If query is ran without specifying database at run-time, this database is used.
     * If either it is not set, default database is used.
     *
     * @param WDB\Database|NULL database
     * @return Query fluent interface
     */
    public function setDatabase(WDB\Database $db = NULL)
    {
        $this->database = $db;
        return $this;
    }

    /**
     * Get currently bound database.
     *
     * @return WDB\Database
     */
    public function getDatabase()
    {
        return $this->database;
    }

    /**
     * Executes the query.
     *
     * @param WDB\Database database to run the query on. If not specified, database bound to query is used. If
     *      either it is not specified, default WDB database is used.
     * @return iQueryResult
     */
    public function run(WDB\Database $database = NULL)
    {
        return $this->getUsedDatabase($database)->query($this);
    }

    /**
     * Get database to run the queries on.
     *
     * Finds first non-null WDB\Database in set:
     * - $db argument
     * - $this->database
     * - WDB\Database::getDefault().
     *
     * @param WDB\Database|NULL database connection
     * @return WDB\Database
     */
    protected function getUsedDatabase(WDB\Database $db = NULL)
    {
        if ($db !== NULL)
        {
            return $db;
        }
        elseif ($this->database !== NULL)
        {
            return $this->database;
        }
        else
        {
            return WDB\Database::getDefault();
        }
    }
    // </editor-fold>

    /**
     * Prints query string translated by database driver from this object and terminates script.
     *
     * @param bool if true, query string is returned instead of printing and script is not terminated.
     * @param WDB\Database|NULL database connection object containing translation driver
     */
    public function debug($return = FALSE, WDB\Database $db = NULL)
    {
        if ($return) return $this->__toString($db);
        echo $this->__toString($db);
        die();
    }

    /**
     * Translate this object to query string by bound database driver.
     *
     * @return string
     */
    public function __toString()
    {
        return $this->getUsedDatabase(NULL)->driver->queryString($this);
    }
}